--- /dev/null
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <asm/uaccess.h>
+
+#include <asm/mtrr.h>
+#include "mtrr.h"
+
+void generic_get_mtrr(unsigned int reg, unsigned long *base,
+ unsigned int *size, mtrr_type * type)
+{
+ dom0_op_t op;
+
+ op.cmd = DOM0_READ_MEMTYPE;
+ op.u.read_memtype.reg = reg;
+ (void)HYPERVISOR_dom0_op(&op);
+
+ *size = op.u.read_memtype.nr_pfns;
+ *base = op.u.read_memtype.pfn;
+ *type = op.u.read_memtype.type;
+}
+
+struct mtrr_ops generic_mtrr_ops = {
+ .use_intel_if = 1,
+ .get = generic_get_mtrr,
+};
+
+struct mtrr_ops *mtrr_if = &generic_mtrr_ops;
+unsigned int num_var_ranges;
+unsigned int *usage_table;
+
+void __init set_num_var_ranges(void)
+{
+ dom0_op_t op;
+
+ for (num_var_ranges = 0; ; num_var_ranges++) {
+ op.cmd = DOM0_READ_MEMTYPE;
+ op.u.read_memtype.reg = num_var_ranges;
+ if (HYPERVISOR_dom0_op(&op) != 0)
+ break;
+ }
+}
+
+static void __init init_table(void)
+{
+ int i, max;
+
+ max = num_var_ranges;
+ if ((usage_table = kmalloc(max * sizeof *usage_table, GFP_KERNEL))
+ == NULL) {
+ printk(KERN_ERR "mtrr: could not allocate\n");
+ return;
+ }
+ for (i = 0; i < max; i++)
+ usage_table[i] = 0;
+}
+
+int mtrr_add_page(unsigned long base, unsigned long size,
+ unsigned int type, char increment)
+{
+ int error;
+ dom0_op_t op;
+
+ op.cmd = DOM0_ADD_MEMTYPE;
+ op.u.add_memtype.pfn = base;
+ op.u.add_memtype.nr_pfns = size;
+ op.u.add_memtype.type = type;
+ if ((error = HYPERVISOR_dom0_op(&op)))
+ return error;
+
+ if (increment)
+ ++usage_table[op.u.add_memtype.reg];
+
+ return op.u.add_memtype.reg;
+}
+
+int
+mtrr_add(unsigned long base, unsigned long size, unsigned int type,
+ char increment)
+{
+ if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
+ printk(KERN_WARNING "mtrr: size and base must be multiples of 4 kiB\n");
+ printk(KERN_DEBUG "mtrr: size: 0x%lx base: 0x%lx\n", size, base);
+ return -EINVAL;
+ }
+ return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type,
+ increment);
+}
+
+int mtrr_del_page(int reg, unsigned long base, unsigned long size)
+{
+ int i, max;
+ mtrr_type ltype;
+ unsigned long lbase;
+ unsigned int lsize;
+ int error = -EINVAL;
+ dom0_op_t op;
+
+ max = num_var_ranges;
+ if (reg < 0) {
+ /* Search for existing MTRR */
+ for (i = 0; i < max; ++i) {
+ mtrr_if->get(i, &lbase, &lsize, <ype);
+ if (lbase == base && lsize == size) {
+ reg = i;
+ break;
+ }
+ }
+ if (reg < 0) {
+ printk(KERN_DEBUG "mtrr: no MTRR for %lx000,%lx000 found\n", base,
+ size);
+ goto out;
+ }
+ }
+ if (usage_table[reg] < 1) {
+ printk(KERN_WARNING "mtrr: reg: %d has count=0\n", reg);
+ goto out;
+ }
+ if (--usage_table[reg] < 1) {
+ op.cmd = DOM0_DEL_MEMTYPE;
+ op.u.del_memtype.handle = 0;
+ op.u.add_memtype.reg = reg;
+ (void)HYPERVISOR_dom0_op(&op);
+ }
+ error = reg;
+ out:
+ return error;
+}
+
+int
+mtrr_del(int reg, unsigned long base, unsigned long size)
+{
+ if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
+ printk(KERN_INFO "mtrr: size and base must be multiples of 4 kiB\n");
+ printk(KERN_DEBUG "mtrr: size: 0x%lx base: 0x%lx\n", size, base);
+ return -EINVAL;
+ }
+ return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);
+}
+
+EXPORT_SYMBOL(mtrr_add);
+EXPORT_SYMBOL(mtrr_del);
+
+static int __init mtrr_init(void)
+{
+ struct cpuinfo_x86 *c = &boot_cpu_data;
+
+ if (!(xen_start_info.flags & SIF_PRIVILEGED))
+ return -ENODEV;
+
+ if ((!cpu_has(c, X86_FEATURE_MTRR)) &&
+ (!cpu_has(c, X86_FEATURE_K6_MTRR)) &&
+ (!cpu_has(c, X86_FEATURE_CYRIX_ARR)) &&
+ (!cpu_has(c, X86_FEATURE_CENTAUR_MCR)))
+ return -ENODEV;
+
+ set_num_var_ranges();
+ init_table();
+
+ return 0;
+}
+
+subsys_initcall(mtrr_init);
#include <asm/shadow.h>
#include <public/sched_ctl.h>
+#include <asm/mtrr.h>
+#include "mtrr/mtrr.h"
+
#define TRC_DOM0OP_ENTER_BASE 0x00020000
#define TRC_DOM0OP_LEAVE_BASE 0x00030000
}
break;
+ case DOM0_ADD_MEMTYPE:
+ {
+ ret = mtrr_add_page(
+ op->u.add_memtype.pfn,
+ op->u.add_memtype.nr_pfns,
+ op->u.add_memtype.type,
+ 1);
+ }
+ break;
+
+ case DOM0_DEL_MEMTYPE:
+ {
+ ret = mtrr_del_page(op->u.del_memtype.reg, 0, 0);
+ }
+ break;
+
+ case DOM0_READ_MEMTYPE:
+ {
+ unsigned long pfn;
+ unsigned int nr_pfns;
+ mtrr_type type;
+
+ ret = -EINVAL;
+ if ( op->u.read_memtype.reg < num_var_ranges )
+ {
+ mtrr_if->get(op->u.read_memtype.reg, &pfn, &nr_pfns, &type);
+ (void)__put_user(pfn, &u_dom0_op->u.read_memtype.pfn);
+ (void)__put_user(nr_pfns, &u_dom0_op->u.read_memtype.nr_pfns);
+ (void)__put_user(type, &u_dom0_op->u.read_memtype.type);
+ ret = 0;
+ }
+ }
+ break;
+
default:
ret = -ENOSYS;
u32 type; /* 8: vm_assist cmd */
} PACKED dom0_setdomainvmassist_t; /* 12 bytes */
+/*
+ * Request memory range (@pfn, @pfn+@nr_pfns-1) to have type @type.
+ * On x86, @type is an architecture-defined MTRR memory type.
+ * On success, returns the MTRR that was used (@reg) and a handle that can
+ * be passed to DOM0_DEL_MEMTYPE to accurately tear down the new setting.
+ * (x86-specific).
+ */
+#define DOM0_ADD_MEMTYPE 31
+typedef struct {
+ /* IN variables. */
+ memory_t pfn; /* 0 */
+ MEMORY_PADDING;
+ memory_t nr_pfns; /* 8 */
+ MEMORY_PADDING;
+ u32 type; /* 16 */
+ u32 __pad0;
+ /* OUT variables. */
+ u32 handle; /* 24 */
+ u32 reg; /* 28 */
+} PACKED dom0_add_memtype_t; /* 32 bytes */
+
+/*
+ * Tear down an existing memory-range type. If @handle is remembered then it
+ * should be passed in to accurately tear down the correct setting (in case
+ * of overlapping memory regions with differing types). If it is not known
+ * then @handle should be set to zero. In all cases @reg must be set.
+ * (x86-specific).
+ */
+#define DOM0_DEL_MEMTYPE 32
+typedef struct {
+ /* IN variables. */
+ u32 handle; /* 0 */
+ u32 reg; /* 4 */
+} PACKED dom0_del_memtype_t; /* 8 bytes */
+
+/* Read current type of an MTRR (x86-specific). */
+#define DOM0_READ_MEMTYPE 33
+typedef struct {
+ /* IN variables. */
+ u32 reg; /* 0 */
+ u32 __pad0;
+ /* OUT variables. */
+ memory_t pfn; /* 8 */
+ MEMORY_PADDING;
+ memory_t nr_pfns; /* 16 */
+ MEMORY_PADDING;
+ u32 type; /* 24 */
+ u32 __pad1;
+} PACKED dom0_read_memtype_t; /* 32 bytes */
+
typedef struct {
u32 cmd; /* 0 */
u32 interface_version; /* 4 */ /* DOM0_INTERFACE_VERSION */
dom0_setdomainmaxmem_t setdomainmaxmem;
dom0_getpageframeinfo2_t getpageframeinfo2;
dom0_setdomainvmassist_t setdomainvmassist;
+ dom0_add_memtype_t add_memtype;
+ dom0_del_memtype_t del_memtype;
+ dom0_read_memtype_t read_memtype;
} PACKED u;
} PACKED dom0_op_t; /* 80 bytes */